Refactor to chained DI, migrate to uv, add vehicles router#2
Refactor to chained DI, migrate to uv, add vehicles router#2adamontherun wants to merge 7 commits intomainfrom
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
- database.py: lazy get_engine() so unit tests need no DATABASE_URL - main.py: load_dotenv() at top so uvicorn loads .env - test_create_character_invalid_data: override CharactersService to avoid DB chain - tests/integration_tests/conftest.py: sync integration_client with transaction rollback - Integration tests use integration_client fixture - README: DI chain, testing strategy, uv setup (no async references) Co-authored-by: Cursor <cursoragent@cursor.com>
- main.py: include vehicles_router, wire SwapiVehicleError and vehicle_not_found_error_handler - StarWarsVehicleCreate: require only name (matches character pattern, service fetches from SWAPI) - StarWarsVehicleRead: optional fields, remove pilots (never populated) - SwapiVehicle: optional fields for SWAPI response parsing Co-authored-by: Cursor <cursoragent@cursor.com>
…omain, utils The DI chain rewrite dropped context about Pydantic schemas, SQLAlchemy models, networking clients, domain logic, and utils. Added it back as a compact section between project layout and naming. Co-authored-by: Cursor <cursoragent@cursor.com>
| with TestClient(app) as client: | ||
| yield client | ||
|
|
||
| txn.rollback() |
There was a problem hiding this comment.
This may not completely rollback all of the underlying changes with the generated session if some commit was made during its usage, be careful on creating tests that may somehow rely on uniqueness or counting depending on how the commit is used inside the services, as an example, I would recommend that mostly of the time no self.db.commit/self.db.rollback should be handled inside the service
andrelopesmds
left a comment
There was a problem hiding this comment.
The chained dependency injection looks good to me. I think the mental model of "this POST /character router is resolved by character service" and you don't care how or if it writes to X or Y DB, uses a 3rd party or not. Imo this is much more readable than passing the DB along all the way.
Also, patching functions everywhere gave me headaches in the past, even changing the import style might break tests. Good stuff getting rid of it.
| swapi_json = get_character_from_swapi(input_character.name) | ||
| swapi_character = transform_swapi_character_json_to_pydantic(swapi_json) | ||
| swapi_character.name = format_star_wars_name(swapi_character.name) | ||
| new_character: StarWarsCharacter = self.db_client.insert_new_character( |
There was a problem hiding this comment.
This is a bit redundant since this insert_new_character function is annotated already.
| new_character: StarWarsCharacter = self.db_client.insert_new_character( | |
| new_character = self.db_client.insert_new_character( |
| swapi_json = get_vehicle_from_swapi(input_vehicle.name) | ||
| swapi_vehicle = transform_swapi_vehicle_json_to_pydantic(swapi_json) | ||
| swapi_vehicle.efficiency = calculate_vehicle_efficiency(swapi_vehicle) | ||
| new_vehicle: StarWarsVehicle = self.db_client.insert_new_vehicle(swapi_vehicle) |
Summary
Depends(). Router tests override the service; service tests inject a mock DB client; DB client tests inject a mock session.requirements.txtwithpyproject.tomlanduv sync.DATABASE_URL. Integration tests use a real Postgres session with transaction rollback.load_dotenv()inmain.pysouvicornloads.env.vehicles_router, fixedSwapiVehicleErrorandVehicleNotFoundErrorhandlers, simplified vehicle schemas to match the character pattern (create needs onlyname).